package com.exercise.widgets.floatingbutton.floatview

import android.app.Activity
import android.content.Context
import android.os.Handler
import android.os.Looper
import android.util.AttributeSet
import android.util.DisplayMetrics
import android.view.MotionEvent
import android.view.View
import android.view.View.OnTouchListener
import android.view.ViewConfiguration
import android.view.WindowManager
import android.view.animation.DecelerateInterpolator
import android.widget.FrameLayout
import kotlin.math.abs
import kotlin.math.roundToInt

abstract class BaseFloatView @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyleAttr: Int = 0
) : FrameLayout(context, attrs, defStyleAttr), OnTouchListener {
    companion object {
        var ADSORB_VERTICAL = 1001
        var ADSORB_HORIZONTAL = 1002
    }

    private var mTouchSlop: Int = 0
    private var mViewWidth = 0
    private var mViewHeight = 0
    private var mToolBarHeight = dp2px(56F)
    private var mDragDistance = 0.5 //默认吸边需要的拖拽距离为屏幕的一半

    private var mDownX: Float = 0f
    private var mDownY: Float = 0f
    private var mFirstX: Int = 0
    private var mFirstY: Int = 0
    private var isMove = false

    private var mIsInside = false
    private var mHandler = Handler(Looper.getMainLooper())

    /**
     * 多久自动缩一半
     * 默认: 3000，单位: 毫秒, 小于等于0则不自动缩回
     */
    open fun getAdsorbTime(): Long {
        return 3000
    }

    protected abstract fun getChildView(): View
    protected abstract fun getAdsorbType(): Int
    protected abstract fun getIsCanDrag(): Boolean

    /**
     * 点击事件
     */
    interface OnFloatClickListener {
        fun onClick(v: View)
    }

    protected var mOnFloatClickListener: OnFloatClickListener? = null
    fun setOnFloatClickListener(listener: OnFloatClickListener) {
        this.mOnFloatClickListener = listener
    }

    /**
     * 自定缩到屏幕内一半,目前只支持（水平方向），垂直方向需要改参数
     */
    private val mRunnable = Runnable {
        if (x > getScreenWidth() / 2) {
            animate()
                .setInterpolator(DecelerateInterpolator())
                .setDuration(300)
                .alpha(0.5f)
                .x((getScreenWidth() - mViewWidth / 2).toFloat())
                .start()
        } else {
            //左边
            animate()
                .setInterpolator(DecelerateInterpolator())
                .setDuration(300)
                .alpha(0.5f)
                .x((-mViewWidth / 2).toFloat())
                .start()
        }
        mIsInside = true
    }

    fun setDragDistance(distance: Double) {
        mDragDistance = distance
    }

    init {
        initView()
    }

    private fun initView() {
        mTouchSlop = ViewConfiguration.get(context).scaledTouchSlop
        val lp = LayoutParams(
            LayoutParams.WRAP_CONTENT,
            LayoutParams.WRAP_CONTENT
        )
        lp.topMargin = mToolBarHeight
        layoutParams = lp

        val childView = getChildView()
        addView(childView)
        setOnTouchListener(this)

        post {
            mViewWidth = this.width
            mViewHeight = this.height
        }
    }

    override fun onTouch(v: View, event: MotionEvent): Boolean {
        val x = event.x
        val y = event.y
        when (event.action) {
            MotionEvent.ACTION_DOWN -> {
                mDownX = event.x
                mDownY = event.y
                //记录首次触摸在屏幕上的位置，用于计算初始位置
                mFirstX = event.rawX.roundToInt()
                mFirstY = event.rawY.roundToInt()

                mHandler.removeCallbacksAndMessages(mRunnable)
                resetStatus()
            }

            MotionEvent.ACTION_MOVE -> {
                isMove = true
                offsetLeftAndRight((x - mDownX).toInt())
                offsetTopAndBottom((y - mDownY).toInt())
            }

            MotionEvent.ACTION_UP -> {
                if (isMove) {
                    if (getAdsorbType() == ADSORB_HORIZONTAL) {
                        adsorbLeftAndRight(event)
                    } else if (getAdsorbType() == ADSORB_VERTICAL) {
                        adsorbTopAndBottom(event)
                    }
                } else {
                    mOnFloatClickListener?.onClick(v)
                }
                isMove = false
                if (getAdsorbTime() > 0) {
                    mHandler.postDelayed(mRunnable, getAdsorbTime())
                }
            }
        }
        return getIsCanDrag()
    }

    private fun resetStatus() {
        if (mIsInside) {
            if (x > getScreenWidth() / 2) {
                // 右边
                animate()
                    .setInterpolator(DecelerateInterpolator())
                    .setDuration(300)
                    .alpha(1f)
                    .x((getScreenWidth() - mViewWidth).toFloat())
                    .start()
            } else {
                // 左边
                animate()
                    .setInterpolator(DecelerateInterpolator())
                    .setDuration(300)
                    .alpha(1f)
                    .x(0f)
                    .start()
            }
            mIsInside = false
        }
    }

    /**
     * 左右吸边
     */
    private fun adsorbLeftAndRight(event: MotionEvent) {
        /**
         * 1.判断滑动距离是否超过半屏
         * 2.判断起始位置在左/右半屏
         * 3.左半屏
         *      3.1 滑动距离<半屏=吸左
         *      3.2 滑动距离>半屏=吸右
         * 4.右半屏
         *      4.1 滑动距离<半屏=吸右
         *      4.2 滑动距离>半屏=吸左
         */
        if (isOriginalFromLeft()) {
            //左半屏
            val centerX = mViewWidth / 2 + abs(event.rawX - mFirstX)
            if (centerX < getAdsorbWidth()) {
                //滑动距离<半屏=吸左
                val leftX = 0f
                animate()
                    .setInterpolator(DecelerateInterpolator())
                    .setDuration(300)
                    .x(leftX)
                    .start()
            } else {
                //滑动距离>半屏=吸右
                val rightX = getScreenWidth() - mViewWidth
                animate()
                    .setInterpolator(DecelerateInterpolator())
                    .setDuration(300)
                    .x(rightX.toFloat())
                    .start()
            }
        } else {
            //右半屏
            val centerX = mViewWidth / 2 + abs(event.rawX - mFirstX)
            if (centerX < getAdsorbWidth()) {
                //滑动距离<半屏=吸右
                val rightX = getScreenWidth() - mViewWidth
                animate()
                    .setInterpolator(DecelerateInterpolator())
                    .setDuration(300)
                    .x(rightX.toFloat())
                    .start()
            } else {
                //滑动距离>半屏=吸左
                val leftX = 0f
                animate()
                    .setInterpolator(DecelerateInterpolator())
                    .setDuration(300)
                    .x(leftX)
                    .start()
            }
        }
        resetVertical(event)
    }

    /**
     * 左右拖拽时，如果纵向拖拽距离超出屏幕，则左右吸边时上下也吸边
     */
    private fun resetVertical(event: MotionEvent) {
        if (event.rawY < mViewHeight) {
            val topY = 0F + mToolBarHeight
            animate().setInterpolator(DecelerateInterpolator()).setDuration(300).y(topY).start()
        } else if (event.rawY > getContentHeight() - mViewHeight) {
            val bottomY = getContentHeight().toFloat() - mViewHeight
            animate().setInterpolator(DecelerateInterpolator()).setDuration(300).y(bottomY).start()
        }
    }

    /**
     * 上下吸边
     */
    private fun adsorbTopAndBottom(event: MotionEvent) {
        /**
         * 1.判断滑动距离是否超过半屏
         * 2.判断起始位置在上/下半屏
         * 3.上半屏：
         *      3.1 滑动距离<半屏=吸顶
         *      3.2 滑动距离>半屏=吸底
         * 4.下半屏:
         *      4.1 滑动距离<半屏=吸底
         *      4.2 滑动距离>半屏=吸顶
         */
        if (isOriginalFromTop()) {
            //上半屏
            val centerY = mViewHeight / 2 + abs(event.rawY - mFirstY)
            if (centerY < getAdsorbHeight()) {
                //滑动距离<半屏=吸顶
                val topY = 0F + mToolBarHeight
                animate().setInterpolator(DecelerateInterpolator()).setDuration(300).y(topY).start()
            } else {
                //滑动距离>半屏=吸底
                val bottomY = getContentHeight() - mViewHeight
                animate().setInterpolator(DecelerateInterpolator()).setDuration(300)
                    .y(bottomY.toFloat()).start()
            }
        } else {
            //下半屏
            val centerY = mViewHeight / 2 + abs(event.rawY - mFirstY)
            if (centerY < getAdsorbHeight()) {
                //滑动距离<半屏=吸底
                val bottomY = getContentHeight() - mViewHeight
                animate().setInterpolator(DecelerateInterpolator()).setDuration(300)
                    .y(bottomY.toFloat()).start()
            } else {
                //滑动距离>半屏=吸顶
                val topY = 0F + mToolBarHeight
                animate().setInterpolator(DecelerateInterpolator()).setDuration(300).y(topY).start()
            }
        }
        resetHorizontal(event)
    }

    /**
     * 上下拖拽时，如果水平拖拽距离超出屏幕，则上下吸边时左右也吸边
     */
    private fun resetHorizontal(event: MotionEvent) {
        if (event.rawX < mViewWidth) {
            val leftX = 0F
            animate().setInterpolator(DecelerateInterpolator()).setDuration(300).x(leftX).start()
        } else if (event.rawX > getScreenWidth() - mViewWidth) {
            val rightX = getScreenWidth().toFloat() - mViewWidth
            animate().setInterpolator(DecelerateInterpolator()).setDuration(300).x(rightX).start()
        }
    }

    /**
     * 是否所到屏幕内
     */
    fun isInside(): Boolean {
        return mIsInside
    }

    /**
     * 获取上下吸边时需要拖拽的距离
     */
    private fun getAdsorbHeight(): Double {
        return getScreenHeight() * mDragDistance
    }

    /**
     * 获取左右吸边时需要拖拽的距离
     */
    private fun getAdsorbWidth(): Double {
        return getScreenWidth() * mDragDistance
    }

    /**
     * 初始位置是否在顶部
     */
    private fun isOriginalFromTop(): Boolean {
        return mFirstY < getScreenHeight() / 2
    }

    /**
     * 初始位置是否在左边
     */
    private fun isOriginalFromLeft(): Boolean {
        return mFirstX < getScreenWidth() / 2
    }

    /**
     * 获取屏幕宽度
     */
    private fun getScreenWidth(): Int {
        val dm = DisplayMetrics()
        (context as? Activity)?.windowManager?.defaultDisplay?.getMetrics(dm)
        return dm.widthPixels
    }

    /**
     * 获取屏幕高度
     */
    private fun getScreenHeight(): Int {
        val dm = DisplayMetrics()
        (context as? Activity)?.windowManager?.defaultDisplay?.getMetrics(dm)
        return dm.heightPixels
    }

    /**
     * 获取页面内容高度
     */
    private fun getContentHeight(): Int {
        val contentView =
            (context as? Activity)?.window?.decorView?.findViewById<FrameLayout>(android.R.id.content)
        return contentView?.bottom ?: 0
    }

    /**
     * dp2px
     */
    private fun dp2px(dp: Float): Int {
        val density = context.resources.displayMetrics.density
        return (dp * density).toInt()
    }

    fun release() {

    }
}